#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
练习题26: 上下文管理器协议(__enter__, __exit__)完整练习

知识点:
- 上下文管理器协议的实现
- with语句的工作原理
- 异常处理和资源清理
- contextlib模块的使用
- 装饰器形式的上下文管理器
- 异步上下文管理器
- 嵌套上下文管理器

难度: ★★★☆☆
"""

import os
import time
import threading
import contextlib
from typing import Any, Optional, Type, Generator
from pathlib import Path


# =============================================================================
# 1. 基础上下文管理器
# =============================================================================

class FileManager:
    """
    文件管理器上下文管理器
    
    TODO: 实现文件管理的上下文管理器
    - 自动打开和关闭文件
    - 处理文件操作异常
    - 支持不同的文件模式
    """
    
    def __init__(self, filename: str, mode: str = 'r', encoding: str = 'utf-8'):
        self.filename = filename
        self.mode = mode
        self.encoding = encoding
        self.file = None
    
    def __enter__(self):
        # TODO: 实现文件打开逻辑
        # 提示: 打开文件并返回文件对象
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 实现文件关闭逻辑
        # 提示: 关闭文件，处理异常情况
        pass


class DatabaseTransaction:
    """
    数据库事务上下文管理器
    
    TODO: 实现数据库事务管理
    - 自动开始事务
    - 成功时提交事务
    - 异常时回滚事务
    """
    
    def __init__(self, connection):
        self.connection = connection
        self.transaction_started = False
    
    def __enter__(self):
        # TODO: 开始事务
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 处理事务结束
        # 提示: 根据是否有异常决定提交或回滚
        pass


class TimerContext:
    """
    计时器上下文管理器
    
    TODO: 实现代码执行时间测量
    - 记录进入时间
    - 计算执行时长
    - 可选的时间格式化
    """
    
    def __init__(self, name: str = "操作", show_result: bool = True):
        self.name = name
        self.show_result = show_result
        self.start_time = None
        self.end_time = None
        self.duration = None
    
    def __enter__(self):
        # TODO: 记录开始时间
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 计算并显示执行时间
        pass
    
    def get_duration(self):
        # TODO: 返回执行时长
        pass


# =============================================================================
# 2. 资源管理上下文管理器
# =============================================================================

class TemporaryDirectory:
    """
    临时目录上下文管理器
    
    TODO: 实现临时目录管理
    - 创建临时目录
    - 自动清理临时文件
    - 支持自定义目录前缀
    """
    
    def __init__(self, prefix: str = "tmp_", base_dir: str = "/tmp"):
        self.prefix = prefix
        self.base_dir = base_dir
        self.temp_dir = None
    
    def __enter__(self):
        # TODO: 创建临时目录
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 清理临时目录
        pass


class LockManager:
    """
    锁管理器上下文管理器
    
    TODO: 实现线程锁管理
    - 自动获取锁
    - 自动释放锁
    - 支持超时机制
    """
    
    def __init__(self, lock: threading.Lock, timeout: Optional[float] = None):
        self.lock = lock
        self.timeout = timeout
        self.acquired = False
    
    def __enter__(self):
        # TODO: 获取锁
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 释放锁
        pass


class EnvironmentVariable:
    """
    环境变量上下文管理器
    
    TODO: 实现临时环境变量设置
    - 临时设置环境变量
    - 自动恢复原始值
    - 支持多个变量同时设置
    """
    
    def __init__(self, **env_vars):
        self.env_vars = env_vars
        self.original_values = {}
    
    def __enter__(self):
        # TODO: 设置环境变量并保存原始值
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 恢复原始环境变量
        pass


# =============================================================================
# 3. 装饰器形式的上下文管理器
# =============================================================================

@contextlib.contextmanager
def change_directory(path: str) -> Generator[str, None, None]:
    """
    临时改变工作目录的上下文管理器
    
    TODO: 实现目录切换功能
    - 保存当前目录
    - 切换到指定目录
    - 自动恢复原目录
    """
    # TODO: 实现目录切换逻辑
    pass


@contextlib.contextmanager
def suppress_stdout() -> Generator[None, None, None]:
    """
    抑制标准输出的上下文管理器
    
    TODO: 实现输出抑制功能
    - 临时重定向stdout
    - 自动恢复原始输出
    """
    # TODO: 实现输出抑制逻辑
    pass


@contextlib.contextmanager
def retry_on_exception(max_retries: int = 3, delay: float = 1.0) -> Generator[None, None, None]:
    """
    异常重试上下文管理器
    
    TODO: 实现异常重试功能
    - 捕获异常并重试
    - 支持最大重试次数
    - 支持重试延迟
    """
    # TODO: 实现重试逻辑
    pass


@contextlib.contextmanager
def log_execution(logger, level: str = "INFO") -> Generator[None, None, None]:
    """
    执行日志上下文管理器
    
    TODO: 实现执行日志记录
    - 记录开始和结束
    - 记录执行时间
    - 记录异常信息
    """
    # TODO: 实现日志记录逻辑
    pass


# =============================================================================
# 4. 高级上下文管理器
# =============================================================================

class NestedContextManager:
    """
    嵌套上下文管理器
    
    TODO: 实现多个上下文管理器的嵌套使用
    - 支持动态添加上下文管理器
    - 正确处理嵌套异常
    - 保证资源正确释放
    """
    
    def __init__(self):
        self.contexts = []
        self.entered_contexts = []
    
    def add_context(self, context_manager):
        # TODO: 添加上下文管理器
        pass
    
    def __enter__(self):
        # TODO: 依次进入所有上下文
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 反向退出所有上下文
        pass


class ConditionalContext:
    """
    条件上下文管理器
    
    TODO: 实现条件性的上下文管理
    - 根据条件决定是否启用上下文
    - 支持动态条件判断
    """
    
    def __init__(self, context_manager, condition):
        self.context_manager = context_manager
        self.condition = condition
        self.active = False
        self.result = None
    
    def __enter__(self):
        # TODO: 根据条件决定是否进入上下文
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 条件性退出上下文
        pass


class ResourcePool:
    """
    资源池上下文管理器
    
    TODO: 实现资源池管理
    - 自动获取和释放资源
    - 支持资源限制
    - 支持资源复用
    """
    
    def __init__(self, resource_factory, max_size: int = 10):
        self.resource_factory = resource_factory
        self.max_size = max_size
        self.available_resources = []
        self.used_resources = set()
        self.lock = threading.Lock()
    
    def __enter__(self):
        # TODO: 获取资源
        pass
    
    def __exit__(self, exc_type, exc_value, traceback):
        # TODO: 释放资源
        pass
    
    def _create_resource(self):
        # TODO: 创建新资源
        pass
    
    def _cleanup_resource(self, resource):
        # TODO: 清理资源
        pass


# =============================================================================
# 5. 异步上下文管理器
# =============================================================================

class AsyncFileManager:
    """
    异步文件管理器
    
    TODO: 实现异步上下文管理器
    - 异步文件操作
    - 异步资源清理
    """
    
    def __init__(self, filename: str, mode: str = 'r'):
        self.filename = filename
        self.mode = mode
        self.file = None
    
    async def __aenter__(self):
        # TODO: 异步进入上下文
        pass
    
    async def __aexit__(self, exc_type, exc_value, traceback):
        # TODO: 异步退出上下文
        pass


class AsyncDatabaseConnection:
    """
    异步数据库连接管理器
    
    TODO: 实现异步数据库连接管理
    - 异步连接建立
    - 异步事务处理
    - 异步连接关闭
    """
    
    def __init__(self, connection_string: str):
        self.connection_string = connection_string
        self.connection = None
    
    async def __aenter__(self):
        # TODO: 异步建立连接
        pass
    
    async def __aexit__(self, exc_type, exc_value, traceback):
        # TODO: 异步关闭连接
        pass


# =============================================================================
# 6. 实用工具类
# =============================================================================

class MockDatabase:
    """
    模拟数据库类（用于演示）
    """
    def __init__(self):
        self.connected = False
        self.in_transaction = False
        self.data = {}
    
    def connect(self):
        self.connected = True
        print("数据库连接已建立")
    
    def disconnect(self):
        self.connected = False
        print("数据库连接已关闭")
    
    def begin_transaction(self):
        if not self.connected:
            raise Exception("数据库未连接")
        self.in_transaction = True
        print("事务已开始")
    
    def commit(self):
        if not self.in_transaction:
            raise Exception("没有活动事务")
        self.in_transaction = False
        print("事务已提交")
    
    def rollback(self):
        if not self.in_transaction:
            raise Exception("没有活动事务")
        self.in_transaction = False
        print("事务已回滚")


class MockResource:
    """
    模拟资源类（用于演示）
    """
    def __init__(self, name: str):
        self.name = name
        self.in_use = False
    
    def acquire(self):
        if self.in_use:
            raise Exception(f"资源 {self.name} 已被使用")
        self.in_use = True
        print(f"资源 {self.name} 已获取")
    
    def release(self):
        if not self.in_use:
            raise Exception(f"资源 {self.name} 未被使用")
        self.in_use = False
        print(f"资源 {self.name} 已释放")


# =============================================================================
# 7. 演示函数
# =============================================================================

def demonstrate_basic_context_managers():
    """
    演示基础上下文管理器
    """
    print("=" * 60)
    print("基础上下文管理器演示")
    print("=" * 60)
    
    # 1. 文件管理器演示
    print("\n1. 文件管理器演示:")
    # TODO: 使用FileManager读写文件
    
    # 2. 数据库事务演示
    print("\n2. 数据库事务演示:")
    # TODO: 使用DatabaseTransaction管理事务
    
    # 3. 计时器演示
    print("\n3. 计时器演示:")
    # TODO: 使用TimerContext测量执行时间


def demonstrate_resource_managers():
    """
    演示资源管理上下文管理器
    """
    print("\n=" * 60)
    print("资源管理上下文管理器演示")
    print("=" * 60)
    
    # 1. 临时目录演示
    print("\n1. 临时目录演示:")
    # TODO: 使用TemporaryDirectory创建临时目录
    
    # 2. 锁管理器演示
    print("\n2. 锁管理器演示:")
    # TODO: 使用LockManager管理线程锁
    
    # 3. 环境变量演示
    print("\n3. 环境变量演示:")
    # TODO: 使用EnvironmentVariable临时设置环境变量


def demonstrate_decorator_context_managers():
    """
    演示装饰器形式的上下文管理器
    """
    print("\n=" * 60)
    print("装饰器形式上下文管理器演示")
    print("=" * 60)
    
    # 1. 目录切换演示
    print("\n1. 目录切换演示:")
    # TODO: 使用change_directory切换目录
    
    # 2. 输出抑制演示
    print("\n2. 输出抑制演示:")
    # TODO: 使用suppress_stdout抑制输出
    
    # 3. 异常重试演示
    print("\n3. 异常重试演示:")
    # TODO: 使用retry_on_exception重试操作


def demonstrate_advanced_context_managers():
    """
    演示高级上下文管理器
    """
    print("\n=" * 60)
    print("高级上下文管理器演示")
    print("=" * 60)
    
    # 1. 嵌套上下文管理器演示
    print("\n1. 嵌套上下文管理器演示:")
    # TODO: 使用NestedContextManager管理多个上下文
    
    # 2. 条件上下文管理器演示
    print("\n2. 条件上下文管理器演示:")
    # TODO: 使用ConditionalContext条件性管理上下文
    
    # 3. 资源池演示
    print("\n3. 资源池演示:")
    # TODO: 使用ResourcePool管理资源池


async def demonstrate_async_context_managers():
    """
    演示异步上下文管理器
    """
    print("\n=" * 60)
    print("异步上下文管理器演示")
    print("=" * 60)
    
    # 1. 异步文件管理器演示
    print("\n1. 异步文件管理器演示:")
    # TODO: 使用AsyncFileManager异步处理文件
    
    # 2. 异步数据库连接演示
    print("\n2. 异步数据库连接演示:")
    # TODO: 使用AsyncDatabaseConnection异步管理连接


def test_context_manager_error_handling():
    """
    测试上下文管理器的异常处理
    """
    print("\n=== 异常处理测试 ===")
    
    # TODO: 测试各种异常情况下的资源清理
    # 1. 测试文件操作异常
    # 2. 测试数据库事务异常
    # 3. 测试资源获取异常
    
    pass


def test_context_manager_nesting():
    """
    测试上下文管理器嵌套
    """
    print("\n=== 嵌套测试 ===")
    
    # TODO: 测试多层嵌套的上下文管理器
    # 1. 测试正常嵌套
    # 2. 测试异常时的嵌套清理
    # 3. 测试资源依赖关系
    
    pass


if __name__ == "__main__":
    # 运行基础演示
    demonstrate_basic_context_managers()
    
    # 运行资源管理演示
    demonstrate_resource_managers()
    
    # 运行装饰器演示
    demonstrate_decorator_context_managers()
    
    # 运行高级演示
    demonstrate_advanced_context_managers()
    
    # 运行异步演示（需要asyncio）
    import asyncio
    asyncio.run(demonstrate_async_context_managers())
    
    # 运行测试
    test_context_manager_error_handling()
    test_context_manager_nesting()
    
    print("\n" + "=" * 60)
    print("练习提示:")
    print("1. 理解上下文管理器协议的工作原理")
    print("2. 掌握资源管理和异常处理的最佳实践")
    print("3. 学会使用contextlib简化上下文管理器实现")
    print("4. 了解异步上下文管理器的使用场景")
    print("5. 探索嵌套和条件上下文管理器的高级用法")
    print("=" * 60)
